package org.knot.mockejb3.plugin.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

/**
 * 
 * 用户事务处理类
 * 
 * @author yuxiaowei
 *
 */
public class MockUserTransaction implements UserTransaction {

    List<Transaction> txs = null;
    
    SessionFactory[]  sessionFactorys = null;
    
    private boolean beginCalled;
    private boolean commitCalled;
    private boolean rollbackCalled;
    private boolean rollbackOnlyCalled;
    private int transactionTimeout;
    private int beginCalls;
    private int commitCalls;
    private int rollbackCalls;
    private int rollbackOnlyCalls;
    
    private int count;
    
    public MockUserTransaction(SessionFactory[] sessionFactorys) {
        reset();
        this.sessionFactorys = sessionFactorys;
    }

    public void reset() {
        beginCalled = false;
        commitCalled = false;
        rollbackCalled = false;
        rollbackOnlyCalled = false;
        transactionTimeout = 0;
        beginCalls = 0;
        commitCalls = 0;
        rollbackCalls = 0;
        rollbackOnlyCalls = 0;
        count = 0;
    }

    public boolean wasBeginCalled() {
        return beginCalled;
    }

    public boolean wasCommitCalled() {
        return commitCalled;
    }

    public boolean wasRollbackCalled() {
        return rollbackCalled;
    }

    public boolean wasRollbackOnlyCalled() {
        return rollbackOnlyCalled;
    }

    public int getTransactionTimeout() {
        return transactionTimeout;
    }

    public int getNumberBeginCalls() {
        return beginCalls;
    }

    public int getNumberCommitCalls() {
        return commitCalls;
    }

    public int getNumberRollbackCalls() {
        return rollbackCalls;
    }

    public int getNumberRollbackOnlyCalls() {
        return rollbackOnlyCalls;
    }

    public int getStatus() throws SystemException {
        if (rollbackCalled)
            return 4;
        if (commitCalled)
            return 3;
        if (rollbackOnlyCalled)
            return 1;
        return !beginCalled ? 6 : 0;
    }

    public void begin() throws NotSupportedException, SystemException {
        beginCalled = true;
        commitCalled = false;
        rollbackCalled = false;
        rollbackOnlyCalled = false;
        beginCalls++;
        
        if (count == 0)
        {
            txs =  new ArrayList<Transaction>();
            for (SessionFactory sf : sessionFactorys)
            {
                Transaction tx = sf.getCurrentSession().beginTransaction();
                txs.add(tx);
                tx.begin();
            }
        }
        count++;
    }

    public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException,
            IllegalStateException, SystemException {
        commitCalled = true;
        commitCalls++;
        --count;
        
        if(count  == 0)
        { 
            for (Transaction tx : txs)
            {
                tx.commit();
            }
        }
        
    }

    public void rollback() throws IllegalStateException, SecurityException, SystemException {
        rollbackCalled = true;
        rollbackCalls++;
        --count;
        if(count  == 0)
        { 
            for (Transaction tx : txs)
            {
                tx.rollback();
            }
        }
    }

    public void setRollbackOnly() throws IllegalStateException, SystemException {
        rollbackOnlyCalled = true;
        rollbackOnlyCalls++;
    }

    public void setTransactionTimeout(int i) throws SystemException {
        transactionTimeout = i;
    }

}
